package com.cash.app.utils

import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty

object SpUtils {
    private lateinit var sharedPreferences: SharedPreferences
    private const val DEFAULT_SP_NAME = "SpUtils"

    /**
     * Initialization with default SharedPreferences p_name
     */
    fun init(context: Context, name: String = DEFAULT_SP_NAME, mode: Int = Context.MODE_PRIVATE) {
        sharedPreferences = context.getSharedPreferences(name, mode)
    }

    private fun checkInitialized() {
        if (!::sharedPreferences.isInitialized) {
            throw IllegalStateException("SpUtils must be initialized first.")
        }
    }

    /**
     * Store data
     * Synchronous operations
     */
    fun <T> put(key: String, value: T) {
        with(sharedPreferences.edit()) {
            when (value) {
                is String -> putString(key, value)
                is Int -> putInt(key, value)
                is Long -> putLong(key, value)
                is Float -> putFloat(key, value)
                is Boolean -> putBoolean(key, value)
                else -> throw IllegalArgumentException("Put Unsupported type: ${value?.let { it.javaClass } ?: "null"}")
            }.apply()
        }
    }

    /**
     * Retrieve data
     */
    @Suppress("UNCHECKED_CAST")
    fun <T> get(key: String, default: T): T {
        with(sharedPreferences) {
            return when (default) {
                is String -> getString(key, default) as T
                is Int -> getInt(key, default) as T
                is Long -> getLong(key, default) as T
                is Float -> getFloat(key, default) as T
                is Boolean -> getBoolean(key, default) as T
                else -> throw IllegalArgumentException("Get Unsupported type: ${default?.let { it.javaClass } ?: "null"}")
            }
        }
    }

    /**
     * Remove a specific key
     */
    fun remove(key: String) {
        sharedPreferences.edit { remove(key) }
    }

    /**
     * Clear all data
     */
    fun clear() {
        sharedPreferences.edit { clear() }
    }

    /**
     * Asynchronously store data
     */
    suspend fun <T> putAsync(key: String, value: T) = withContext(Dispatchers.IO) {
        put(key, value)
    }

    /**
     * Asynchronously retrieve data
     */
    suspend fun <T> getAsync(key: String, default: T): T = withContext(Dispatchers.IO) {
        get(key, default)
    }

    // region Property delegation extensions
    /**
     * String type property delegate
     */
    fun stringPref(key: String, default: String = "") = SharedPreferencesProperty(key, default)

    /**
     * Int type property delegate
     */
    fun intPref(key: String, default: Int = 0) = SharedPreferencesProperty(key, default)

    /**
     * Long type property delegate
     */
    fun longPref(key: String, default: Long = 0L) = SharedPreferencesProperty(key, default)

    /**
     * Float type property delegate
     */
    fun floatPref(key: String, default: Float = 0f) = SharedPreferencesProperty(key, default)

    /**
     * Boolean type property delegate
     */
    fun booleanPref(key: String, default: Boolean = false) = SharedPreferencesProperty(key, default)

    class SharedPreferencesProperty<T>(
        private val key: String, private val default: T
    ) : ReadWriteProperty<Any?, T> {
        override fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return get(key, default)
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
            put(key, value)
        }
    }
}